using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace GameStateManagement
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class DrawableObject : Microsoft.Xna.Framework.DrawableGameComponent
    {
        public bool hasChanged;
        public Matrix worldTransformMatrix;
        public Model actorModel;
        public Effect celShader;
        public bool followCam;
        public Matrix[] actorBones;
        public GameStateManagementGame game;
        public BoundingSphere ModelBounds;
        public BoundingSphere WorldBounds;
        public float fScale;
        public Vector3 vWorldPosition;
        public Quaternion qRotation;
        public ContentManager contentManager;
        public Texture2D texture;

        public DrawableObject(Game game)
            : base(game)
        {
            // TODO: Construct any child components here
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        /// 

        public void updateWorldTransformMatrix()
        {
            hasChanged = false;

            Matrix scaleMatrix = Matrix.CreateScale(fScale);
            Matrix rotationMatrix = Matrix.CreateFromQuaternion(qRotation);
            Matrix translationMatrix = Matrix.CreateTranslation(vWorldPosition);

            worldTransformMatrix = scaleMatrix;
            worldTransformMatrix *= rotationMatrix;
            worldTransformMatrix *= translationMatrix;

            WorldBounds.Center = vWorldPosition;
            WorldBounds.Radius = ModelBounds.Radius * fScale;
        }

        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            if (hasChanged)
            {
                updateWorldTransformMatrix();
                hasChanged = false;
            }

            actorModel.CopyAbsoluteBoneTransformsTo(actorBones);

            GraphicsDevice.RenderState.DepthBufferEnable = true;

            if (game.useNormalTarget)
            {
                celShader.CurrentTechnique = celShader.Techniques["NormalDepth"];
            }
            else
            {
                celShader.CurrentTechnique = celShader.Techniques["Toon"];
            }

            foreach (ModelMesh mesh in actorModel.Meshes)
            {
                foreach (Effect effect in mesh.Effects)
                {
                    effect.Parameters["world"].SetValue(actorBones[mesh.ParentBone.Index] * worldTransformMatrix);
                    if (followCam)
                    {
                        effect.Parameters["view"].SetValue(GameplayScreen.camera.View);
                        effect.Parameters["projection"].SetValue(GameplayScreen.camera.Projection);
                    }
                    else
                    {
                        effect.Parameters["view"].SetValue(GameplayScreen.CameraMatrix);
                        effect.Parameters["projection"].SetValue(GameplayScreen.ProjectionMatrix);
                    }

                    float[] thresholds = new float[2] { 12.0f, 0.005f };
                    effect.Parameters["toonThresholds"].SetValue(thresholds);
                }
                mesh.Draw();
            }
            base.Draw(gameTime);


        }

        protected void changeEffectUsedByModel(Model m, Effect e)
        {
            foreach (ModelMesh mesh in m.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    part.Effect = e;
                }
            }
        }
    }
}